package com.xx.app.config.realm;

import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.xx.app.config.jwt.token.JwtToken;
import com.xx.app.config.jwt.utils.JwtUtils;
import com.xx.app.vo.AppLoginUser;
import com.xx.common.core.redis.RedisCache;
import com.xx.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 自定义AppRealm 处理登录权限
 */
@Slf4j
public class AppUserRealm extends AuthorizingRealm {

    @Autowired
    private RedisCache redisCache;

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return new SimpleAuthorizationInfo();
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws JWTVerificationException, AuthenticationException {
        JwtToken jwtToken = (JwtToken) authenticationToken;
        String token = jwtToken.getToken();
        String address = JwtUtils.getAddress(token);
        if (StringUtils.isEmpty(address)) {
            throw new AccountException("用户不存在");
        }

        Object obj = redisCache.getLoginUserByAddress(address);
        AppLoginUser appLoginUser;
        if (obj instanceof AppLoginUser) {
            appLoginUser = (AppLoginUser) obj;
        } else {
            throw new AuthenticationException("获取用户信息异常");
        }
        String signature = redisCache.getSignatureByAddress(address);
        if (signature == null) {
            throw new AuthenticationException("用户签名不存在");
        }
        try {
            // jwt 认证
            JwtUtils.verify(address, signature, token);
        } catch (TokenExpiredException e) {
            throw new TokenExpiredException("token已过期");
        } catch (JWTVerificationException e) {
            throw new JWTVerificationException("用户签名错误");
        } catch (Exception e) {
            throw new UnknownAccountException("用户信息验证失败：" + e.getMessage());
        }
        JwtUtils.refreshToken(appLoginUser, address, token, signature, redisCache);
        return new SimpleAuthenticationInfo(token, token, getName());
    }

}
